/*
 * Copyright 2007-2009 Thomas Krause (thomas@berlin-reloaded.de)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.gidoo.cms.jcr;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import javax.jcr.ImportUUIDBehavior;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import org.gidoo.cms.admin.addins.BackupPanel;
import org.gidoo.cms.login.GidooCMSSession;

/**
 * Handles import and export of backups
 * @author <a href="mailto:thomas@berlin-reloaded.de">Thomas Krause</a>
 */
public class BackupManager
{

  public static final int BACKUP_FILE_VERSION = 4;

  /**
   * Import a backup from a file.
   * @param file The ZIP-file to use.
   * @param s The GidooCMSSession context.
   * @return True if successfull, false if not.
   */
  public static boolean importCMSFromFile(File file, GidooCMSSession s)
  {
    if(file != null && file.isFile() && file.canRead())
    {
      try
      {
        ZipFile zf = new ZipFile(file);
        // check version
        ZipEntry zeVersion = zf.getEntry("version");
        ZipEntry zeDrafts = zf.getEntry("drafts.xml");
        ZipEntry zeUsers = zf.getEntry("users.xml");
        ZipEntry zeSections = zf.getEntry("sections.xml");
        ZipEntry zePrivateDrafts = zf.getEntry("private_drafts.xml");

        if(zeVersion == null || zeDrafts == null || zeUsers == null || zeSections == null)
        {
          s.error(getI18N(s).getString("structerror"));
        }
        else
        {
          ObjectInputStream in = new ObjectInputStream(zf.getInputStream(zeVersion));
          int version = in.readInt();
          in.close();

          if(version == 1 || version == 2 || version == 3 || version == 4)
          {
            Session session = s.getJcrSession();

            InputStream draftIn = zf.getInputStream(zeDrafts);
            InputStream usersIn = zf.getInputStream(zeUsers);
            InputStream sectionsIn = zf.getInputStream(zeSections);
            InputStream privateDraftsIn = null;
            if(zePrivateDrafts != null)
            {
              privateDraftsIn = zf.getInputStream(zePrivateDrafts);
            }
            // delete old nodes
            Node rootNode = session.getRootNode();

            if(rootNode.hasNode("drafts"))
            {
              rootNode.getNode("drafts").remove();
            }
            if(rootNode.hasNode("users"))
            {
              rootNode.getNode("users").remove();
            }
            if(rootNode.hasNode("sections"))
            {
              rootNode.getNode("sections").remove();
            }
            if(rootNode.hasNode("private_drafts"))
            {
              rootNode.getNode("private_drafts").remove();
            }

            // add "new" nodes
            session.importXML("/", draftIn, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
            session.importXML("/", usersIn, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
            session.importXML("/", sectionsIn, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
            if(privateDraftsIn == null)
            {
              rootNode.addNode("private_drafts");
            }
            else
            {
              session.importXML("/", privateDraftsIn, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
            }

            session.save();

            return true;
          }
          else
          {
            s.error(getI18N(s).getString("versionerror"));
          }
        }
      }
      catch(RepositoryException ex)
      {
        Logger.getLogger(BackupPanel.class.getName()).log(Level.SEVERE, null, ex);
        s.error(getI18N(s).getString("jcrerror"));
      }
      catch(IOException ex)
      {
        Logger.getLogger(BackupPanel.class.getName()).log(Level.SEVERE, null, ex);
        s.error(getI18N(s).getString("ioerror"));
      }
    }
    else
    {
      s.error(getI18N(s).getString("ioerror"));
    }

    return false;
  }

  /**
   * Exports the CMS (not including the version history) to a temporary ZIP-file.
   * @param s The GidooCMSSession context.
   * @return The temporary file to where this function exported the CMS
   *         or <code>null</code> if an error occured.
   */
  public static File exportCMS(GidooCMSSession s)
  {
    try
    {
      Session session = s.getJcrSession();

      // zip it together to one file
      File tmpZipFile = File.createTempFile("cmsBackupTmp", ".zip");
      tmpZipFile.deleteOnExit();
      ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(tmpZipFile));

      // write content and user data
      ZipEntry zeVersion = new ZipEntry("version");
      zout.putNextEntry(zeVersion);
      ObjectOutputStream o = new ObjectOutputStream(zout);
      o.writeInt(BACKUP_FILE_VERSION);
      o.flush();
      zout.closeEntry();

      ZipEntry zeTmp = new ZipEntry("drafts.xml");
      zout.putNextEntry(zeTmp);
      session.exportSystemView("/drafts", zout, false, false);
      zout.closeEntry();

      zeTmp = new ZipEntry("private_drafts.xml");
      zout.putNextEntry(zeTmp);
      session.exportSystemView("/private_drafts", zout, false, false);
      zout.closeEntry();

      zeTmp = new ZipEntry("users.xml");
      zout.putNextEntry(zeTmp);
      session.exportSystemView("/users", zout, false, false);
      zout.closeEntry();

      zeTmp = new ZipEntry("sections.xml");
      zout.putNextEntry(zeTmp);
      session.exportSystemView("/sections", zout, false, false);
      zout.closeEntry();

      zout.close();

      return tmpZipFile;
      

    }
    catch(IOException ex)
    {
      Logger.getLogger(BackupPanel.class.getName()).log(Level.SEVERE, null, ex);
      s.error(getI18N(s).getString("ioerror"));
    }
    catch(RepositoryException ex)
    {
      Logger.getLogger(BackupPanel.class.getName()).log(Level.SEVERE, null, ex);
      s.error(getI18N(s).getString("jcrerror"));
    }
    return null;
  }

  public static ResourceBundle getI18N(org.apache.wicket.Session session)
  {
    return java.util.ResourceBundle.getBundle("org/gidoo/cms/jcr/I18N", session.getLocale());
  }
}
